
#include "Grid.h"
#include "core/utils.h"
#include "core/BinaryHeap.h"
#include <stdio.h>
#include <iostream>


Grid::Grid(void)
	:map(),width(),height(),nodes(),blockVal()
{
}


Grid::~Grid(void)
{
	// if (map)
	// {
	// 	for (uint32 i=0;i<height;++i)
	// 	{
	// 		delete [] map[i];
	// 	}
	// 	delete [] map;
	// }

	if (nodes)
	{
		for (uint32 i=0;i<height;++i)
		{
			for (uint32 j=0;j<width;++j)
			{
				delete nodes[i][j];
			}
			delete []nodes[i];
		}
		delete []nodes;
	}
}

// bool Grid::initWithFile( const char* mapFilePath,int8 blockVal )
// {
// 	FILE* fp =  NULL;
// 	fp = fopen(mapFilePath,"r");
// 	if (!fp) return false;
	
// 	unsigned char * buffer = NULL;
// 	size_t size = 0;
// 	fseek(fp,0,SEEK_END);
// 	size = ftell(fp);
// 	fseek(fp,0,SEEK_SET);
// 	buffer = (unsigned char*)malloc(size);
// 	memset(buffer,0,size*sizeof(unsigned char));
// 	size = fread(buffer,sizeof(unsigned char), size,fp);
// 	fclose(fp);

// 	std::string str((const char*)buffer);
// 	free(buffer);
// 	setBlockVal(blockVal);
// 	return initWithString(str);	
// }

// bool Grid::initWithString( std::string& str )
// {
// 	map=utils::stringMapToArray(str,width,height);
// 	if (!map || !initNodes())
// 		return false;
// 	return true;
// }

bool Grid::initNodes()
{
	nodes = new AStarNode**[height];
	//std::cout<<"map data-------------------------->"<<endl;
	for (uint32 i=0;i<height;++i)
	{
		nodes[i] = new AStarNode*[width];
		for (uint32 j=0;j<width;++j)
		{
			nodes[i][j] = new AStarNode();
			uint8 val = 0;
			uint32 index = i * width + j;
			uint8 byte = (uint8)map[index / 8];
			uint8 bitIndex = (index % 8);
			val = ((byte >> bitIndex) % 2);	
			// nodes[i][j]->init(j,i,blockVal==map[i][j]);
			nodes[i][j]->init(j,i,blockVal==val);
			//std::cout<< map[i][j] <<",";
		}
		//std::cout << endl;
	}
	//std::cout<<"<--------------------------map data"<<endl;

	return true;
}

bool Grid::isWalkAbleAt( uint32 x,uint32 y )
{
	if(outOfMap(x,y)) return false;
	AStarNode* n = nodes[y][x];
	return !(n->isBlock);
}

bool Grid::outOfMap( uint32 x,uint32 y )
{
	if (x >= width || y >= height)
		return true;
	return false;
}

void Grid::setBlockVal( int val )
{
	blockVal = val;
}

void Grid::getNeighbours( std::vector<AStarNode*>& neighbours,AStarNode* node,bool allowDiagonal,bool tunnel )
{
	if(!node) return;
	neighbours.clear();
	for (int i=0;i<4;++i)
	{
		int x = node->x + straightOffsets[i][0];
		int y = node->y + straightOffsets[i][1];
		AStarNode* n = getNodeAt(x,y);
		if (!n) continue;
		if (isWalkAbleAt(n->x,n->y))
		{
			neighbours.push_back(n);
		}
	}
	if(!allowDiagonal) return;

	for (int i=0;i<4;++i)
	{
		int x = node->x + diagonalOffsets[i][0];
		int y = node->y + diagonalOffsets[i][1];


		AStarNode* n = getNodeAt(x,y);
		if(!n) continue;

		if (isWalkAbleAt(n->x,n->y))
		{
			if(tunnel)
				neighbours.push_back(n);
			else
			{				
				AStarNode* n1 = getNodeAt(x,node->y);
				AStarNode* n2 = getNodeAt(node->x,y);
				if (n1&&n2)
				{
					if (isWalkAbleAt(n1->x,n1->y) && isWalkAbleAt(n2->x,n2->y))
					{
						neighbours.push_back(n);
					}
				}			
			}
		}
	}
}

AStarNode* Grid::getNodeAt( int x,int y )
{
	if (outOfMap(x,y)) return NULL;

	return nodes[y][x];
}

// bool Grid::initWithTalbe( int8** tb,int8 _blockVal,int width,int height )
bool Grid::initWithTalbe( const char* tb,int8 _blockVal,int width,int height )
{
	map = tb;
	// std::cout << "~~~~~~~~~" << tb << std::endl;
	setBlockVal(_blockVal);
	this->width = width;
	this->height = height;

	if (!map || !initNodes())
		return false;
	return true;
}

void Grid::setNodeAt(int index, int value)
{
	int y = index / width;
	int x = index % width;
	if (outOfMap(x,y)) return;
	AStarNode* node = nodes[y][x];
	node->isBlock = (value == blockVal);
}
